﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Crm.Sdk.Messages;

/**
 * Copyright 2011 by Alberto Gemin
 * agemin@hotmail.com
 * Version 1.2.0.1
 * 19 Dec 2011
 **/
namespace Gemina.CRM2011.WF.CrmDistributeWF
{
    [AgCodeActivity("Distribute Many to Many", "DWF AG Utilities")]
    public sealed class DistributeWFActivityManytoMany : DistributeWFActivity
    {

        protected override List<Guid> GatherKeys(CodeActivityContext executionContext)
        {
            ManyToManyRelationshipMetadata relationship = this.GetRelationship(executionContext);

            string primaryAttribute;
            string secondaryEntity;
            string secondaryAttribute;
            string intersection = relationship.IntersectEntityName;
            if (relationship.Entity1LogicalName == this.CurrentEntityName)
            {
                // entity1 is primary
                primaryAttribute = relationship.Entity1IntersectAttribute;
                secondaryEntity = relationship.Entity2LogicalName;
                secondaryAttribute = relationship.Entity2IntersectAttribute;
            }
            else
            {
                // entity2 is primary
                primaryAttribute = relationship.Entity2IntersectAttribute;
                secondaryEntity = relationship.Entity1LogicalName;
                secondaryAttribute = relationship.Entity1IntersectAttribute;
            }

            QueryExpression query = new QueryExpression();
            LinkEntity secondaryToIntersection = new LinkEntity();
            LinkEntity intersectionToPrimary = new LinkEntity();
            ConditionExpression primaryCondition = new ConditionExpression();

            // Chain all links
            query.EntityName = secondaryEntity;
            query.LinkEntities.Add(secondaryToIntersection);
            secondaryToIntersection.LinkEntities.Add(intersectionToPrimary);
            intersectionToPrimary.LinkCriteria.Conditions.Add(primaryCondition);

            // First link
            secondaryToIntersection.LinkToEntityName = intersection;
            secondaryToIntersection.LinkFromAttributeName =
            secondaryToIntersection.LinkToAttributeName = secondaryAttribute;

            // Second link
            intersectionToPrimary.LinkToEntityName = this.CurrentEntityName;
            intersectionToPrimary.LinkFromAttributeName =
            intersectionToPrimary.LinkToAttributeName = primaryAttribute;

            // Condition
            primaryCondition.AttributeName = primaryAttribute;
            primaryCondition.Operator = ConditionOperator.Equal;
            primaryCondition.Values.Add(this.CurrentRecordId.ToString());

            RetrieveMultipleRequest retrieveRequest = new RetrieveMultipleRequest();
            retrieveRequest.Query = query;

            List<Guid> list = new List<Guid>();
            RetrieveMultipleResponse retrieveResponse = (RetrieveMultipleResponse)this.GetService(executionContext).Execute(retrieveRequest);
            foreach (Entity entity in retrieveResponse.EntityCollection.Entities)
            {
                list.Add(entity.Id);
            }

            return list;
        }

        private ManyToManyRelationshipMetadata GetRelationship(CodeActivityContext executionContext)
        {
            RetrieveRelationshipRequest relationshipRequest = new RetrieveRelationshipRequest();
            relationshipRequest.Name = this.RelationshipName.Get(executionContext);
            relationshipRequest.RetrieveAsIfPublished = false;

            RetrieveRelationshipResponse relationshipResponse = (RetrieveRelationshipResponse)this.GetService(executionContext).Execute(relationshipRequest);
            if (!(relationshipResponse.RelationshipMetadata is ManyToManyRelationshipMetadata))
            {
                throw new AgErrorMessage("Relationship is not Many to Many");
            }
            ManyToManyRelationshipMetadata rel = (ManyToManyRelationshipMetadata)relationshipResponse.RelationshipMetadata;
            return rel;
        }

    }
}
